---
title: Messages
description: Learn how to define messages in PromptL
---

## Overview

Messages are the building blocks of PromptL prompts. They define the flow of conversations between the user, the assistant, and other entities like tools. Each message is associated with a **role** that determines its purpose in the conversation.

PromptL supports the following message roles:
- **System**: Sets the context and rules for the assistant.
- **User**: Represents user input in the conversation.
- **Assistant**: Captures assistant responses or provides context for the LLM's output.
- **Tool**: Represents interactions with external tools or APIs.

---

## Roles

### System Messages
System messages provide high-level instructions and context for the assistant.

```xml
<system>
  You are a personal finance advisor. Provide actionable insights in a friendly tone.
</system>
```

### User Messages
User messages simulate user input in the conversation.

```xml
<user>
  How can I save more money each month?
</user>
```
---

## Tags

### The `<message>` Tag
Messages can be defined using the `<message>` tag with a `role` attribute:

```xml
<message role="system">
  This is a system message.
</message>
```

### Shortcut Tags
For convenience, you can use specific tags for each role:
- `<system>`: Equivalent to `<message role="system">`.
- `<user>`: Equivalent to `<message role="user">`.
- `<assistant>`: Equivalent to `<message role="assistant">`.
- `<tool>`: Equivalent to `<message role="tool">`.

```xml
<system>
  You are a friendly chatbot.
</system>
<user>
  What’s the weather today in Barcelona?
</user>
<assistant>
  Let me check for you!
  <tool-call id="123" name="get-weather" arguments={{ { location: "Barcelona" } }} />
</assistant>
<tool id="123">
  23ºC, sunny.
</tool>
```

---

## Content Types

Messages can contain different types of content. By default, all plain text is considered `text` content, but you can specify other types using the `<content>` tag or its shorthand equivalents.

- **Text (default)**: `<content type="text">` or `<content-text>`.
- **Image**: `<content type="image">` or `<content-image>`. Add the image URL or base64-encoded string – depending on your provider's requirements – as the content inside the tag.
- **File**: `<content type="file">` or `<content-file>`. Add the file URL or base64-encoded string – depending on your provider's requirements – as the content inside the tag. Requires a MIME type `mime` attribute to specify the file type.
- **Tool Call**: `<content type="tool-call">` or `<tool-call>`. Represents a tool invocation with attributes like `id`, `name`, and `arguments` (optional). Only allowed inside assistant messages.

<Note>
  Not all providers and all models will support all content types. Your provider may support files but not all types of files. Check your provider's documentation for compatibility.
</Note>

### Examples
```tsx
<user>
  Take a look at this image:
  <content-image>[image url]</content-image>

  And this PDF:
  <content-file mime="application/pdf">[file url]</content-file>
</user>

<assistant>
  <tool-call id="123" name="get-weather" arguments={{ { location: "Barcelona" } }} />
</assistant>
```

---

## Best Practices

- **Use System Messages for Context**: Define clear rules for the assistant to guide its behavior.
- **Leverage User Messages for Dynamic Input**: Use uncontrolled user variables inside user messages to define a clear difference authority between the user and the system rules.

---

## Advanced Examples

Here’s how multiple message roles and content types can work together:

```tsx
<system>
  You are a helpful assistant for travel planning.
</system>

<user>
  Find me a good restaurant in {{ city }}.
</user>

<assistant>
  Let me check for you.
  <tool-call id="456" name="find-restaurant" arguments={{ { location: city } }} />
</assistant>

<tool id="456">
  The best-rated restaurant in {{ city }} is Gourmet Central.
</tool>
```